package com.yehun.web.websocket;

import com.yehun.entity.Message;
import com.yehun.utils.JsonUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArraySet;

public class SpringWebSocketHandler extends TextWebSocketHandler {

    private final static Logger logger = LoggerFactory.getLogger(SpringWebSocketHandler.class);

    private static volatile int onlineCount = 0;
    private static final CopyOnWriteArraySet<WebSocketSession> webSocketSet = new CopyOnWriteArraySet<>();
    private static final CopyOnWriteArraySet<String> webSocketUsers = new CopyOnWriteArraySet<>();
    private WebSocketSession session;

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        this.session = session;
        addOnlineCount();
        logger.info("userId: {}", this.getUserId());
        webSocketSet.add(session);
        webSocketUsers.add(this.getUserId());
        //sendMessageAll(String.format("%s: 进入", getUserId())); //群发消息
        sendMessageAll(JsonUtils.serialize(new Message(1, webSocketUsers)));
        System.out.println(String.format("有新连接加入!当前在线人数为%d, 当前在线%s", getOnlineCount(), JsonUtils.serialize(webSocketUsers)));
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws IOException {
        this.session = session;
        subOnlineCount();
        webSocketSet.remove(session);
        webSocketUsers.remove(getUserId());
        //sendMessageAll(String.format("%s: 离开", session.getId())); //群发消息
        sendMessageAll(JsonUtils.serialize(new Message(1, webSocketUsers)));
        this.session.close();
        System.out.println(String.format("有一连接关闭!当前在线人数为%d, 当前在线%s", getOnlineCount(), JsonUtils.serialize(webSocketUsers)));
    }

    @Override
    public void handleTextMessage(WebSocketSession session, TextMessage message) throws IOException {
        this.session = session;
        System.out.println(String.format("来自客户端的消息:%s", message.getPayload()));
        Map<String, Object> map = JsonUtils.toObject(message.getPayload(), Map.class);
        String json = JsonUtils.serialize(new Message(String.format("%s: %s", this.getUserId(), map.get("message"))));
        if (map.containsKey("userId")) {
            sendMessage(map.get("userId").toString(), json);
        } else {
            sendMessageAll(json); //群发消息
        }
    }


    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        this.session = session;
        sendMessage(JsonUtils.serialize(new Message(-1, String.format("error: %s", exception.getMessage()))));
        //if (session.isOpen()) {
        //    session.close();
        //    webSocketSet.remove(this);
        //}
        System.out.println("连接出错");
    }

    @Override
    public boolean supportsPartialMessages() {
        return false;
    }


    /**
     * 发送信息给指定用户
     */
    public void sendMessage(String message) {
        System.out.println("sendMessage:" + this.session);
        if (this.session.isOpen()) {
            try {
                this.session.sendMessage(new TextMessage(message));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 发送信息给指定用户
     */
    public void sendMessage(String userId, String message) {
        WebSocketSession newSession = this.findSession(userId);
        if (newSession != null && newSession.isOpen()) {
            try {
                newSession.sendMessage(new TextMessage(message));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 广播信息
     */
    public void sendMessageAll(String message) {
        System.out.println("total: " + webSocketSet.size());
        for (WebSocketSession newSession : webSocketSet) {
            if (newSession.isOpen()) {
                try {
                    newSession.sendMessage(new TextMessage(message));
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public String getUserId() {
        Object object = this.session.getAttributes().get("userId");
        return object == null ? this.session.getId() : object.toString();
    }

    public WebSocketSession findSession(String userId) {
        for (WebSocketSession newSession : webSocketSet) {
            Object object = newSession.getAttributes().get("userId");
            if (object != null && object.toString().equals(userId)) {
                return newSession;
            }
        }
        return null;
    }

    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        SpringWebSocketHandler.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        SpringWebSocketHandler.onlineCount--;
    }
}
